/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package filesecurity;

import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

/**
 *
 * @author lehoangkhanh
 */
public class Crypto {
    
    public static final int DES = 1;
    public static final int AES = 2;
    public static String getAlgo(int i){
        if(i == 1)
            return "DES";
        if(i == 2)
            return "AES";
        return null;
    }
    public static SecretKey decryptKey(byte[] enskey, PrivateKey prikey, int algo){
        byte[] ciphertext = enskey;
        try {
            Cipher cipherDecrypt = Cipher.getInstance("RSA/ECB/PKCS1Padding");
            cipherDecrypt.init(Cipher.DECRYPT_MODE, prikey);
            byte[] plaintext = cipherDecrypt.doFinal(ciphertext); 
            SecretKey originalKey = new SecretKeySpec(plaintext, 0, plaintext.length, getAlgo(algo));
            return originalKey;
        } catch (NoSuchAlgorithmException ex) {
            Logger.getLogger(Crypto.class.getName()).log(Level.SEVERE, null, ex);
        } catch (NoSuchPaddingException ex) {
            Logger.getLogger(Crypto.class.getName()).log(Level.SEVERE, null, ex);
        } catch (InvalidKeyException ex) {
            Logger.getLogger(Crypto.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IllegalBlockSizeException ex) {
            Logger.getLogger(Crypto.class.getName()).log(Level.SEVERE, null, ex);
        } catch (BadPaddingException ex) {
            Logger.getLogger(Crypto.class.getName()).log(Level.SEVERE, null, ex);
        } 
        return null;
    }
    public static byte[] encryptKey(SecretKey skey, PublicKey pubkey){
        byte[] plaintext = skey.getEncoded();
        try {
            Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
            cipher.init(Cipher.ENCRYPT_MODE, pubkey);
            byte[] cipherText = cipher.doFinal(plaintext);
            return cipherText;
        } catch (NoSuchAlgorithmException ex) {
            Logger.getLogger(Crypto.class.getName()).log(Level.SEVERE, null, ex);
        } catch (NoSuchPaddingException ex) {
            Logger.getLogger(Crypto.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IllegalBlockSizeException ex) {
            Logger.getLogger(Crypto.class.getName()).log(Level.SEVERE, null, ex);
        } catch (BadPaddingException ex) {
            Logger.getLogger(Crypto.class.getName()).log(Level.SEVERE, null, ex);
        } catch (InvalidKeyException ex) {
            Logger.getLogger(Crypto.class.getName()).log(Level.SEVERE, null, ex);
        } 
        return null;
    }
    public static byte[] decryptFile(byte[] file, SecretKey key, int algo, byte[] iv){
        try {
            Cipher cipher = null;
            cipher = Cipher.getInstance(getAlgo(algo)+"/CBC/PKCS5Padding");
            IvParameterSpec ivspec = new IvParameterSpec(iv);
            cipher.init(Cipher.DECRYPT_MODE, key, ivspec);
            byte[] cipherText = cipher.doFinal(file);
            return cipherText;
        } catch (NoSuchAlgorithmException ex) {
            Logger.getLogger(Crypto.class.getName()).log(Level.SEVERE, null, ex);
        } catch (NoSuchPaddingException ex) {
            Logger.getLogger(Crypto.class.getName()).log(Level.SEVERE, null, ex);
        } catch (InvalidKeyException ex) {
            Logger.getLogger(Crypto.class.getName()).log(Level.SEVERE, null, ex);
        } catch (InvalidAlgorithmParameterException ex) {
            Logger.getLogger(Crypto.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IllegalBlockSizeException ex) {
            Logger.getLogger(Crypto.class.getName()).log(Level.SEVERE, null, ex);
        } catch (BadPaddingException ex) {
            Logger.getLogger(Crypto.class.getName()).log(Level.SEVERE, null, ex);
        }
        return null;
    }
    public static byte[] encryptFile(byte[] file, SecretKey key, int algo, byte[] iv){
        try {
            Cipher cipher = null;
            cipher = Cipher.getInstance(getAlgo(algo)+"/CBC/PKCS5Padding");
            IvParameterSpec ivspec = new IvParameterSpec(iv);
            cipher.init(Cipher.ENCRYPT_MODE, key, ivspec);
            byte[] cipherText = cipher.doFinal(file);
            return cipherText;
        } catch (NoSuchAlgorithmException ex) {
            Logger.getLogger(Crypto.class.getName()).log(Level.SEVERE, null, ex);
        } catch (NoSuchPaddingException ex) {
            Logger.getLogger(Crypto.class.getName()).log(Level.SEVERE, null, ex);
        } catch (InvalidKeyException ex) {
            Logger.getLogger(Crypto.class.getName()).log(Level.SEVERE, null, ex);
        } catch (InvalidAlgorithmParameterException ex) {
            Logger.getLogger(Crypto.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IllegalBlockSizeException ex) {
            Logger.getLogger(Crypto.class.getName()).log(Level.SEVERE, null, ex);
        } catch (BadPaddingException ex) {
            Logger.getLogger(Crypto.class.getName()).log(Level.SEVERE, null, ex);
        }
        return null;
    }
    public static byte[] hash(byte[] data, byte[] salt){
        try {
            MessageDigest digest = MessageDigest.getInstance("SHA1");
            digest.reset();
            digest.update(salt);
            byte[] hashedBytes = digest.digest(data);
            return hashedBytes;
        } catch (NoSuchAlgorithmException ex) {
            Logger.getLogger(Crypto.class.getName()).log(Level.SEVERE, null, ex);
        }
        return null;
    }
    public static boolean checkHash(byte[] data, byte[] hashcode, byte[] salt){
        MessageDigest md = null;
        try {
            md = MessageDigest.getInstance("SHA1");
            md.reset();
            md.update(salt);
        } catch (NoSuchAlgorithmException ex) {
            Logger.getLogger(Crypto.class.getName()).log(Level.SEVERE, null, ex);
        }
        byte[] hash = md.digest(data);
        final char[] hexArray = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
        
        char[] hexChars = new char[hash.length * 2];
        int v;
        for ( int j = 0; j < hash.length; j++ ) {
            v = hash[j] & 0xFF;
            hexChars[j * 2] = hexArray[v >>> 4];
            hexChars[j * 2 + 1] = hexArray[v & 0x0F];
        }   
        String result = new String(hexChars);
            
        char[] hexChars1 = new char[hashcode.length * 2];
        int v1;
        for ( int j = 0; j < hashcode.length; j++ ) {
            v = hashcode[j] & 0xFF;
            hexChars1[j * 2] = hexArray[v >>> 4];
            hexChars1[j * 2 + 1] = hexArray[v & 0x0F];
        } 
        String result1 = new String(hexChars1);
        
        for(int i=0; i<result1.length(); i++){
            int a = result.charAt(i);
            int b = result1.charAt(i);
            if(a != b)
                return false;
        }
        return true;
    }
    public static byte[] getIV(int algo){
        SecureRandom random = new SecureRandom();
        byte[] bytes = null;
        if(getAlgo(algo) == "DES"){
            bytes = new byte[8];
        }
        if(getAlgo(algo) == "AES"){
            bytes = new byte[16];
        }
        random.nextBytes(bytes);
        return bytes;   
    }
    public static byte[] getSalt(){
        SecureRandom random = new SecureRandom();
        byte bytes[] = new byte[20];
        random.nextBytes(bytes);
        return bytes;
    }
}
